package io.itit.ecp.admin.provide.action.controller.miniprogram;


import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.enums.IMeterDeviceEnums;
import io.itit.ecp.admin.common.enums.ProductTypeActiveStatus;
import io.itit.ecp.admin.provide.action.resp.largescreen.CarbonReductionStatisticsResp;
import io.itit.ecp.admin.provide.action.resp.largescreen.ReductionCarbonSinkTrends;
import io.itit.ecp.admin.server.entity.EnergyDataEntity;
import io.itit.ecp.admin.server.entity.MeterDeviceEntity;
import io.itit.ecp.admin.server.entity.ProductTypeEntity;
import io.itit.ecp.admin.server.service.IProductTypeService;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 碳减
 */
@Api(tags = {"碳减"})
@RestController
@RequiredArgsConstructor
@RequestMapping("/mini/emissionReduction")
public class MiniEmissionReductionController {

    @Resource
    private IProductTypeService productTypeService;

    /**
     * 碳减总量
     */
    @ApiOperation("碳减总量")
    @GetMapping("total")
    public ResultResp<Map<String, Object>> getTotal(@RequestParam(required = false) String sceneProjectId,
                                                    @RequestParam(required = false) String sceneEdificeId,
                                                    @RequestParam(required = false) String sceneFloorId,
                                                    @RequestParam(required = false) String startTime,
                                                    @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.isNotEmpty(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.isNotEmpty(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        BigDecimal value = Joins.of(EnergyDataEntity.class)
                .selectAs(consumer -> consumer
                        .add("SUM(carbon_emission)", "carbonEmission", false)
                )
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .in(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.isNotEmpty(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.isNotEmpty(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.isNotEmpty(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(EnergyDataEntity::getSolidifyDate, end)
                .joinGetOne(BigDecimal.class);
        value = ObjectUtils.defaultIfNull(value, BigDecimal.ZERO).setScale(2, RoundingMode.HALF_DOWN);
        String unit = "kgce";
        BigDecimal t = new BigDecimal("1000");
        if (value.compareTo(t) >= 0) {
            unit = "tce";
            value = value.divide(t, 2, RoundingMode.HALF_DOWN);
        }
        Map<String, Object> result = new HashMap<>();
        result.put("value", value);
        result.put("unit", unit);
        return ResultResp.success(result);
    }

    /**
     * 碳减排趋势
     *
     * @param sceneProjectId sceneProjectId
     * @param sceneEdificeId sceneEdificeId
     * @param sceneFloorId   sceneFloorId
     * @param type           type 0：时；1：日
     * @param startTime      startTime
     * @param endTime        endTime
     */
    @ApiOperation("碳减排趋势")
    @GetMapping("reductioncarbontrends")
    public ResultResp<List<ReductionCarbonSinkTrends>> reductionCarbonTrends(@RequestParam(required = false) String sceneProjectId,
                                                                             @RequestParam(required = false) String sceneEdificeId,
                                                                             @RequestParam(required = false) String sceneFloorId,
                                                                             @RequestParam String type,
                                                                             @RequestParam(required = false) String startTime,
                                                                             @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.isNotEmpty(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.isNotEmpty(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        List<EnergyDataEntity> energyDataEntities = Joins.of(EnergyDataEntity.class)
                .select(EnergyDataEntity::getSolidifyDate, EnergyDataEntity::getCarbonEmission)
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .in(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(org.springframework.util.StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(org.springframework.util.StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(org.springframework.util.StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(EnergyDataEntity::getSolidifyDate, end)
                .orderByAsc(EnergyDataEntity::getSolidifyDate)
                .joinList(EnergyDataEntity.class);
        List<ReductionCarbonSinkTrends> trends = new ArrayList<>();
        String dateFormat = "yyyy-MM-dd HH:00";
        if (org.springframework.util.StringUtils.pathEquals("1", type)) {
            dateFormat = "yyyy-MM-dd";
        }
        String unit = "kgCO2";
        String finalFormat = dateFormat;
        Map<String, List<EnergyDataEntity>> groupBySolidifyDateMap = energyDataEntities.stream()
                .collect(Collectors.groupingBy(item -> DateUtil.format(item.getSolidifyDate(), finalFormat), TreeMap::new, Collectors.toList()));
        List<ReductionCarbonSinkTrends.DataDetail> dataDetailList = new ArrayList<>();
        for (Map.Entry<String, List<EnergyDataEntity>> entry : groupBySolidifyDateMap.entrySet()) {
            dataDetailList.add(new ReductionCarbonSinkTrends.DataDetail().setTime(entry.getKey()).setValue(entry.getValue()
                    .stream()
                    .map(EnergyDataEntity::getCarbonEmission)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP)));
        }
        trends.add(new ReductionCarbonSinkTrends().setName("减排量").setUnit(unit).setData(dataDetailList));
        BigDecimal t = new BigDecimal("1000");
        if (trends.stream()
                .anyMatch(item -> item.getData()
                        .stream()
                        .anyMatch(dataItem -> dataItem.getValue().compareTo(t) >= 0))) {
            unit = "tCO2";
            for (ReductionCarbonSinkTrends item : trends) {
                item.setUnit(unit);
                for (ReductionCarbonSinkTrends.DataDetail dateItem : item.getData()) {
                    dateItem.setValue(dateItem.getValue().divide(t, 2, RoundingMode.HALF_UP));
                }
            }
        }
        return ResultResp.success(trends);
    }

    /**
     * 碳减统计
     *
     * @param sceneProjectId sceneProjectId
     * @param sceneEdificeId sceneEdificeId
     * @param sceneFloorId   sceneFloorId
     * @param startTime      startTime
     * @param endTime        endTime
     */
    @ApiOperation("碳减统计")
    @GetMapping("carbonReductionStatistics")
    public ResultResp<List<CarbonReductionStatisticsResp>> carbonReductionStatistics(@RequestParam(required = false) String sceneProjectId,
                                                                                     @RequestParam(required = false) String sceneEdificeId,
                                                                                     @RequestParam(required = false) String sceneFloorId,
                                                                                     @RequestParam(required = false) String startTime,
                                                                                     @RequestParam(required = false) String endTime) {
        LocalDateTime start = org.springframework.util.StringUtils.hasLength(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = org.springframework.util.StringUtils.hasLength(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        List<CarbonReductionStatisticsResp> dataList = new ArrayList<>();
        String unit = "kgCO2";
        BigDecimal t = new BigDecimal("1000");
        List<ProductTypeEntity> productTypeEntities = productTypeService.list(new LambdaQueryWrapper<ProductTypeEntity>()
                .eq(ProductTypeEntity::getActiveStatus, ProductTypeActiveStatus.ENABLED.getValue())
                .orderByAsc(ProductTypeEntity::getSort));
        List<EnergyDataEntity> energyDataEntities = Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder.add("ecp_tt_energy_data.product_type_id", "product_type_id", false)
                        .add("carbon_emission", "carbon_emission", false)
                        .add("solidify_date", "solidify_date", false)
                )
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .in(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .isNotNull(EnergyDataEntity::getProductTypeId)
                .eq(org.springframework.util.StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(org.springframework.util.StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getEnergyTypeId, sceneEdificeId)
                .eq(org.springframework.util.StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneEdificeId, sceneFloorId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(EnergyDataEntity::getSolidifyDate, end).joinList(EnergyDataEntity.class);
        TreeMap<String, List<EnergyDataEntity>> dataMap = energyDataEntities.stream().collect(Collectors.groupingBy(item -> DateUtil.format(item.getSolidifyDate(), "yyyy-MM-dd HH:00"), TreeMap::new, Collectors.toList()));
        for (ProductTypeEntity productType : productTypeEntities) {
            List<CarbonReductionStatisticsResp.DataItem> items = new ArrayList<>();
            for (Map.Entry<String, List<EnergyDataEntity>> entry : dataMap.entrySet()) {
                String date = entry.getKey();
                BigDecimal value = entry.getValue().stream().filter(item -> item.getProductTypeId().equals(productType.getId()))
                        .map(EnergyDataEntity::getCarbonEmission)
                        .filter(Objects::nonNull)
                        .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN);
                items.add(new CarbonReductionStatisticsResp.DataItem().setTime(date).setValue(value));
            }
            dataList.add(new CarbonReductionStatisticsResp().setData(items).setUnit(unit).setName(productType.getProductTypeName()));
        }
        if (dataList.stream().anyMatch(item -> item.getData().stream().anyMatch(dataItem -> dataItem.getValue().compareTo(t) >= 0))) {
            unit = "tCO2";
            for (CarbonReductionStatisticsResp statisticsResp : dataList) {
                statisticsResp.setUnit(unit);
                for (CarbonReductionStatisticsResp.DataItem item : statisticsResp.getData()) {
                    item.setValue(item.getValue().divide(t, 2, RoundingMode.HALF_DOWN));
                }
            }
        }
        return ResultResp.success(dataList);
    }
}
